package org.seanye.com.junitrunnerui.util;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * Help to parse jar file
 * 
 * @author seany1
 * 
 */
@SuppressWarnings("unchecked")
public class JarUtil {

	public static final String CLASS = ".class";

	public static List<Class<?>> loadKlasses(String jarPath,
			final String[] classpath) throws Exception {
		File file = new File(jarPath);
		if (file.isFile() && file.canRead()) {
			return loadKlasses(file, classpath);
		} else
			return Collections.EMPTY_LIST;
	}

	private static List<Class<?>> loadKlasses(File file,
			final String[] classpath) throws Exception {
		List<String> classes = findAllClassEntries(file);
		URLClassLoader loader = URLClassLoader.newInstance(createURLs(file,
				classpath));
		List<Class<?>> result = new ArrayList<Class<?>>(classes.size());
		for (String klass : classes) {
			String klassName = klass.replaceAll("/", ".").substring(0,
					klass.length() - CLASS.length());
			Class<?> loadClass = loader.loadClass(klassName);
			result.add(loadClass);
		}
		return result;
	}

	private static URL[] createURLs(File file, final String[] classpath)
			throws MalformedURLException {
		URL[] cls = null;
		if (classpath != null && classpath.length > 0) {
			cls = new URL[classpath.length];
			for (int i = 0; i < classpath.length; i++) {
				cls[i] = new File(classpath[i]).toURL();
			}
		}
		URL[] all = null;
		if (cls != null) {
			all = new URL[cls.length + 1];
			System.arraycopy(cls, 0, all, 0, cls.length);
			all[all.length - 1] = file.toURL();
		} else {
			all = new URL[] { file.toURL() };
		}
		return all;
	}

	private static List<String> findAllClassEntries(File file) throws Exception {
		JarFile jarFile = new JarFile(file);
		Enumeration<JarEntry> entries = jarFile.entries();
		List<String> classes = new ArrayList<String>(jarFile.size());
		for (; entries.hasMoreElements();) {
			JarEntry entry = entries.nextElement();
			String name = entry.getName();
			if (name.endsWith(CLASS)) {
				classes.add(name);
			}
		}
		return classes;
	}
}
